package com.lawyer.uitls;

import java.beans.PropertyDescriptor;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import org.springframework.beans.BeansException;
import org.springframework.beans.FatalBeanException;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

public abstract class BeanUtils extends org.springframework.beans.BeanUtils {

	private static final String CHARSET = "GBK";

	private static final String[] SPECIAL = new String[] { "\"" };

	public static void copyPropertiesIgnoreNullValue(Object source, Object target, String... ignoreProperties) throws BeansException {
		Assert.notNull(source, "Source must not be null");
		Assert.notNull(target, "Target must not be null");
		Class<?> actualEditable = target.getClass();
		PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);
		List<String> ignoreList = (ignoreProperties != null ? Arrays.asList(ignoreProperties) : null);
		for (PropertyDescriptor targetPd : targetPds) {
			if (null != targetPd.getWriteMethod() && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) {
				PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());
				if (null != sourcePd && null != sourcePd.getReadMethod() && !StringUtils.isEmpty(sourcePd.getPropertyType())
						&& sourcePd.getPropertyType().isAssignableFrom(targetPd.getPropertyType())) {
					try {
						Method readMethod = sourcePd.getReadMethod();
						if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
							readMethod.setAccessible(true);
						}
						Object value = readMethod.invoke(source);

						// 这里判断以下value是否为空 当然这里也能进行一些特殊要求的处理 例如绑定时格式转换等等
						if (null != value) {
							Method writeMethod = targetPd.getWriteMethod();
							if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
								writeMethod.setAccessible(true);
							}
							writeMethod.invoke(target, value);
						}
					} catch (Throwable ex) {
						throw new FatalBeanException("Could not copy properties from source to target", ex);
					}
				}
			}

		}
	}

	public static void copyPropertiesIgnoreNullValue(Object source, Object target) throws BeansException {
		copyPropertiesIgnoreNullValue(source, target, (String[]) null);
	}

	public static Field getDeclaredField(Class type, String name) {
		Field beanField = null;
		try {
			beanField = type.getDeclaredField(name);
		} catch (NoSuchFieldException e) {

			return null;
		} catch (SecurityException e) {

			return null;
		}

		return beanField;
	}

	public static Map<Integer, String> getMap(Map<Integer, Map<Integer, String>> values, int index) {
		if (values.get(index) == null) {
			values.put(index, new HashMap<>());
		}
		return values.get(index);
	}

	public static Map<Integer, String> getMap(int index) {
		Map<Integer, Map<Integer, String>> values = new HashMap<>();
		if (values.get(index) == null) {
			values.put(index, new HashMap<>());
		}
		return values.get(index);
	}

	public static String getMapToString(Map<Integer, String> values, int index) {
		return values.get(index) == null ? new String() : values.get(index);
	}

	public static boolean isEmpty(Object o) {
		if (o == null)
			return true;
		if (o instanceof Collection) {
			return ((Collection) o).isEmpty();
		}
		if (o instanceof Map) {
			return ((Map) o).isEmpty();
		}
		if (o instanceof String) {
			return ((String) o).length() <= 0;
		}
		if (o.getClass().isArray()) {
			return ((Object[]) o).length <= 0;
		}
		return false;
	}

	public static boolean isNotEmpty(Object o) {
		return !isEmpty(o);
	}

	public static boolean isNotEmptyAndAll(Object... o) {
		if (isEmpty(o))
			return false;
		for (Object o1 : o) {
			if (isEmpty(o1))
				return false;
		}
		return true;
	}

	public static boolean isEmptyAndAll(Object... o) {
		if (isEmpty(o))
			return true;
		for (Object o1 : o) {
			if (isNotEmpty(o1))
				return false;
		}
		return true;
	}

	/**
	 * 替换字符串中的特殊字符
	 * 
	 * @param obc
	 * @return
	 */
	public static boolean replace(Object obc) {
		return base(obc, (invoke -> {
			for (String s : SPECIAL) {
				invoke = invoke.replaceAll(s, "");
			}
			return invoke;
		}));
	}

	/**
	 * 复制空值
	 * 
	 * @param source
	 * @param target
	 * @return
	 */
	public static boolean beanToCPAndTargetFiledIsNull(Object source, Object target) {
		for (Field field : source.getClass().getDeclaredFields()) {
			Method methodget = null;
			Method targetSetMethod = null;
			Method targetMethod = null;
			Object invoke = null;
			try {
				methodget = source.getClass().getMethod("get" + upperFirstLatter(field.getName()));
				targetSetMethod = target.getClass().getMethod("set" + upperFirstLatter(field.getName()), field.getType());
				targetMethod = target.getClass().getMethod("get" + upperFirstLatter(field.getName()));
				if (methodget != null && targetSetMethod != null && targetMethod != null) {
					invoke = methodget.invoke(source);
					Object invoke1 = targetMethod.invoke(target);
					if (invoke != null && BeanUtils.isEmpty(invoke1)) {
						targetSetMethod.invoke(target, invoke);
					}
				}
			} catch (NoSuchMethodException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				e.printStackTrace();
			}
		}
		return true;
	}

	/**
	 * 复制空值
	 * 
	 * @param source
	 * @param target
	 * @return
	 */
	public static boolean beanToCPAndTargetFiledIsNull(Object source, Object target, String... ignoreProperties) {
		List<String> ignoreList = (ignoreProperties != null ? Arrays.asList(ignoreProperties) : null);
		for (Field field : source.getClass().getDeclaredFields()) {
			if (ignoreList.contains(field.getName())) {
				continue;
			}
			Method methodget = null;
			Method targetSetMethod = null;
			Method targetMethod = null;
			Object invoke = null;

			try {
				methodget = source.getClass().getMethod("get" + upperFirstLatter(field.getName()));
				targetSetMethod = target.getClass().getMethod("set" + upperFirstLatter(field.getName()), field.getType());
				targetMethod = target.getClass().getMethod("get" + upperFirstLatter(field.getName()));
				if (methodget != null && targetSetMethod != null && targetMethod != null) {
					invoke = methodget.invoke(source);
					Object invoke1 = targetMethod.invoke(target);
					if (invoke != null && BeanUtils.isEmpty(invoke1)) {
						targetSetMethod.invoke(target, invoke);
					}
				}
			} catch (NoSuchMethodException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				e.printStackTrace();
			}
		}
		return true;
	}

	/**
	 * 替换首字母大写
	 *
	 * @param letter
	 * @return
	 */
	static private String upperFirstLatter(String letter) {
		return letter.substring(0, 1).toUpperCase() + letter.substring(1);
	}

	/**
	 * 验证长度是否小于
	 * 
	 * @param str
	 * @param length
	 * @return
	 */
	public static boolean validateStringLength(String str, int length) {
		if (null != str && 0 != length) {
			try {
				if (str.getBytes(CHARSET).length <= length)
					return true;
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}
			return false;
		}
		return true;
	}

	/**
	 * 判断是否数字
	 * 
	 * @param str
	 * @return
	 */
	public static boolean isNumber(String str) {
		if (null != str && 0 != str.length()) {
			for (int i = 0; i < str.length(); i++) {
				if (!Character.isDigit(str.charAt(i))) {
					return false;
				}
			}
			return true;
		}
		return false;
	}

	/**
	 * 去除空格
	 * 
	 * @param obc
	 * @return
	 */
	public static boolean trim(Object obc) {
		return base(obc, (in -> {
			int len = in.length();
			int st = 0;
			char[] val = in.toCharArray(); /* avoid getfield opcode */

			while ((st < len) && (val[st] == '　' || val[st] == ' ')) {
				st++;
			}
			while ((st < len) && (val[len - 1] == '　' || val[len - 1] == ' ')) {
				len--;
			}
			return ((st > 0) || (len < in.length())) ? in.substring(st, len) : in;
		}));
	}

	public static boolean base(Object obc, Function function) {
		if (isEmpty(obc))
			return false;
		for (Field field : obc.getClass().getDeclaredFields()) {
			Class<?> type = field.getType();
			if (type.getName().equals("java.lang.String")) {
				Method methodget = null;
				Method methodset = null;
				String invoke = null;
				try {
					methodget = obc.getClass().getMethod("get" + upperFirstLatter(field.getName()));
					methodset = obc.getClass().getMethod("set" + upperFirstLatter(field.getName()), String.class);
					invoke = (String) methodget.invoke(obc);
					if (invoke != null) {
						String s1 = function.doSomeThin(invoke);
						methodset.invoke(obc, s1);
					}
				} catch (NoSuchMethodException e) {
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				} catch (InvocationTargetException e) {
					e.printStackTrace();
				}
			}
		}
		return true;
	}

	public static String concat(String split, String... str) {
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < str.length; i++) {
			if (str[i] != null) {
				sb.append(str[i]);
			}
			if (str != null && i < (str.length - 1))
				sb.append(split);
		}
		return sb.toString();
	}

	@FunctionalInterface
	private static interface Function {

		String doSomeThin(String str);
	}

	/**
	 * @param length
	 *            用户要求产生字符串的长度
	 * @return 随机字符串
	 */
	public static String getRandomString(int length) {
		String str = "23456789ABCDEFGHIJKLMNPQRSTUVWXYZ23456789";
		Random random = new Random();
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < length; i++) {
			int number = random.nextInt(str.length());
			sb.append(str.charAt(number));
		}
		return sb.toString();
	}
}
